home *** CD-ROM | disk | FTP | other *** search
- /* $Header: mbox.c,v 2.5 90/02/23 16:35:55 chip Exp $
- *
- * Finally! Put the message in the specified mailbox(es).
- *
- * $Log: mbox.c,v $
- * Revision 2.5 90/02/23 16:35:55 chip
- * \Fix problems determining legality of user references.
- *
- * Revision 2.4 90/02/23 14:16:50 chip
- * Support "#!" in delivery files.
- * Support "user|program" and "user?error" from delivery files.
- * Improve debugging and error message formatting.
- * Rearrange code for clarity.
- *
- * Revision 2.3 90/02/06 11:56:42 chip
- * Enforce MBX_MODE regardless of UMASK.
- * Enforce ordered logging with a log lockfile.
- * Revise log format.
- *
- * Revision 2.2 89/11/01 11:51:05 network
- * Fix error code; unknown user is now reported correctly.
- *
- * Revision 2.1 89/06/09 12:25:33 network
- * Update RCS revisions.
- *
- * Revision 1.6 89/06/09 12:23:55 network
- * Baseline for 2.0 release.
- *
- */
-
- #include "deliver.h"
- #include <sys/stat.h>
- #include <errno.h>
-
- /*
- * External data.
- */
-
- extern int errno;
-
- /*
- * Local functions.
- */
-
- static prog_one();
- static mbox_one();
- static int mbox_write();
-
- /*----------------------------------------------------------------------
- * Deliver mail to all valid program (pipe) destinations.
- * Return count of programs to which we tried to write.
- */
-
- int
- prog_deliver()
- {
- DEST *d;
- int progcount;
-
- progcount = 0;
- for (d = first_dest(); d; d = next_dest(d))
- {
- if (d->d_state != ST_WORKING)
- continue;
-
- if (d->d_class == CL_PROG)
- {
- prog_one(d);
- ++progcount;
- }
- }
-
- return progcount;
- }
-
- /*----------------------------------------------------------------------
- * Deliver mail to one program.
- */
-
- static
- prog_one(d)
- DEST *d;
- {
- CONTEXT *ct;
- char *av[4];
- int fd;
-
- if (printaddrs)
- (void) printf("%s|%s\n", d->d_name, d->d_param);
-
- if (dryrun)
- {
- d->d_state = ST_DONE;
- return;
- }
-
- if ((ct = name_context(d->d_name)) == NULL)
- {
- dest_err(d, E_NSUSER);
- return;
- }
-
- if (! ok_context(eff_uid, real_uid, real_gid, ct))
- {
- dest_err(d, E_CTPERM);
- return;
- }
-
- av[0] = SHELL;
- av[1] = "-c";
- av[2] = d->d_param;
- av[3] = NULL;
- if ((fd = ct_openv(ct, av[0], av, O_WRONLY)) == -1)
- {
- dest_err(d, E_PIPE);
- return;
- }
-
- (void) lseek(tfd[T_HDR], 0L, 0);
- (void) lseek(tfd[T_BODY], 0L, 0);
- if (copyfd(tfd[T_HDR], fd) < 0 || copyfd(tfd[T_BODY], fd) < 0)
- dest_err(d, E_PIPE);
-
- if (ct_close(fd))
- dest_err(d, E_PROG);
- else
- d->d_state = ST_DONE;
- }
-
- /*----------------------------------------------------------------------
- * Deliver mail to all valid mailbox destinations.
- * Return count of mailboxes to which we tried to write.
- */
-
- int
- mbox_deliver()
- {
- DEST *d;
- int mboxcount;
-
- mboxcount = 0;
- for (d = first_dest(); d; d = next_dest(d))
- {
- if (d->d_state != ST_WORKING)
- continue;
-
- if (d->d_class == CL_USER || d->d_class == CL_MBOX)
- {
- mbox_one(d);
- ++mboxcount;
- }
- }
-
- return mboxcount;
- }
-
- /*----------------------------------------------------------------------
- * Deliver mail to one mailbox destination.
- */
-
- static
- mbox_one(d)
- DEST *d;
- {
- CONTEXT *ct;
- int ret = 0;
-
- if (printaddrs)
- {
- (void) printf("%s", d->d_name);
- if (d->d_class == CL_MBOX)
- (void) printf(":%s", d->d_param);
- (void) printf("\n");
- }
-
- if (dryrun)
- {
- d->d_state = ST_DONE;
- return;
- }
-
- if ((ct = name_context(d->d_name)) == NULL)
- {
- dest_err(d, E_NSUSER);
- return;
- }
-
- if (! ok_context(eff_uid, real_uid, real_gid, ct))
- {
- dest_err(d, E_CTPERM);
- return;
- }
-
- if (d->d_class == CL_MBOX)
- {
- if (sfork() == 0)
- {
- if (become(ct, !boxdelivery) < 0)
- exit(1);
- if (mbox_write(d->d_param, ct, FALSE) < 0)
- exit(1);
- exit(0);
- }
-
- if (await_child() != 0)
- ret = -1;
- }
- else
- {
- char mailbox[100];
-
- (void) sprintf(mailbox, "%s/%s",
- #ifdef MBX_DIR
- MBX_DIR, d->d_name
- #else
- d->d_home, MBX_NAME
- #endif
- );
-
- if (mbox_write(mailbox, ct, TRUE) < 0)
- ret = -1;
- }
-
- if (ret >= 0)
- d->d_state = ST_DONE;
- else
- dest_err(d, E_MBOX);
- }
-
- /*----------------------------------------------------------------------
- * Write mail to the named mailbox.
- * If we have to create the mailbox, give it to the specified user.
- * If "is_sys" is true, then we're writing to a system mailbox.
- */
-
- static int
- mbox_write(mailbox, ct, is_sys)
- char *mailbox;
- CONTEXT *ct;
- int is_sys;
- {
- struct stat st;
- int fd, t, mbox_uid, mbox_gid;
- int ret = 0;
-
- if (verbose)
- {
- message("As %s, delivering to %s mailbox %s\n",
- ct->ct_name, (is_sys ? "system" : "user"), mailbox);
- }
-
- if (name_lock(mailbox) < 0)
- return -1;
-
- while ((fd = open(mailbox, O_WRONLY)) == -1)
- {
- int um;
-
- if (errno != ENOENT)
- {
- syserr("can't open %s", mailbox);
- break;
- }
-
- um = umask(0); /* save old umask; set it to zero */
- #ifdef O_CREAT
- fd = open(mailbox, O_WRONLY|O_CREAT|O_EXCL, MBX_MODE);
- #else
- fd = creat(mailbox, MBX_MODE);
- #endif
- (void) umask(um); /* restore umask; ass_u_me errno unchanged */
-
- if (fd == -1)
- {
- /* If the error is "file already there", try again. */
- if (errno == EEXIST)
- continue;
-
- /* Something is very wrong... */
- syserr("can't create %s", mailbox);
- break;
- }
-
- /* Make sure the mailbox receives the correct modes */
-
- mbox_uid = ct->ct_uid;
- mbox_gid = ct->ct_gid;
-
- #ifdef MBX_GROUP
- if (is_sys)
- {
- static int mbox_sv_gid = -2;
-
- if (mbox_sv_gid == -2)
- mbox_sv_gid = group_id(MBX_GROUP);
-
- if (mbox_sv_gid < 0)
- message("%s: no such group\n", MBX_GROUP);
- else
- mbox_gid = mbox_sv_gid;
- }
- #endif /* MBX_GROUP */
-
- if (fstat(fd, &st) == -1)
- {
- syserr("can't fstat open mailbox?!");
- (void) close(fd);
- fd = -1;
- break;
- }
-
- /* Change mailbox ownership if it's not already correct. */
-
- if ((st.st_uid != mbox_uid || st.st_gid != mbox_gid)
- && chown(mailbox, mbox_uid, mbox_gid) == -1)
- {
- /* print a message, but that's all. (???) */
- syserr("can't chown %s to %d,%d",
- mailbox, mbox_uid, mbox_gid);
- }
-
- /* It's open now, so we can stop looping now. */
-
- break;
- }
-
- if (fd == -1)
- {
- (void) name_unlock(mailbox);
- return -1;
- }
-
- if (fd_lock(fd) < 0)
- {
- (void) close(fd);
- (void) name_unlock(mailbox);
- return -1;
- }
-
- (void) lseek(fd, 0L, 2); /* No error check: may be a special file */
-
- for (t = T_HDR; t <= T_BODY; ++t)
- {
- if (lseek(tfd[t], 0L, 0) == -1)
- {
- syserr("lseek in %s file %s", ttype[t], tfile[t]);
- ret = -1;
- break;
- }
-
- if (copyfd(tfd[t], fd) < 0)
- {
- ret = -1;
- break;
- }
- }
-
- if (verbose)
- {
- if (ret >= 0)
- message("wrote message to %s\n", mailbox);
- }
-
- if (fd_unlock(fd) < 0)
- ret = -1;
- (void) close(fd);
- if (name_unlock(mailbox) < 0)
- ret = -1;
-
- return ret;
- }
-